import cv2
import numpy as np
from collections import deque


class AccidentDetector:
    def __init__(self, bird_view_width=1980, bird_view_height=1020, debug_enabled=False):
        self.bird_view_width = bird_view_width
        self.bird_view_height = bird_view_height
        self.debug_enabled = debug_enabled
        self.detected_accidents = []  # 存储检测到的事故
        self.vehicle_history = {}
        self.lane_polygon = None
        self.min_out_frames = 3
        self.threshold = 0

    def build_lane_polygon(self, left_lane_points, right_lane_points):
        """构建车道区域多边形（严格保持之前正确版本）"""
        if not left_lane_points or not right_lane_points:
            return None

        # 确保左右车道点数量相同
        n_points = min(len(left_lane_points), len(right_lane_points))

        # 找到最底部的点（y坐标最大的点）
        max_y_left = max(p[1] for p in left_lane_points)
        max_y_right = max(p[1] for p in right_lane_points)
        max_y = max(max_y_left, max_y_right)

        # 如果最底部的点没有到达图像底部，则添加垂直延伸
        if max_y < self.bird_view_height - 1:
            # 获取左右车道最底部的点
            left_bottom = next(p for p in left_lane_points if p[1] == max_y_left)
            right_bottom = next(p for p in right_lane_points if p[1] == max_y_right)

            # 创建垂直延伸的点
            left_extension = (left_bottom[0], self.bird_view_height - 1)
            right_extension = (right_bottom[0], self.bird_view_height - 1)
        else:
            # 如果已经到达底部，则不需要添加延伸
            left_extension = None
            right_extension = None

        # 创建车道区域多边形
        polygon_points = []

        # 添加左车道线点（按原始顺序）
        for i in range(n_points):
            polygon_points.append(left_lane_points[i])

        # 如果添加了左车道延伸点
        if left_extension:
            polygon_points.append(left_extension)

        # 添加右车道延伸点（如果有）
        if right_extension:
            polygon_points.append(right_extension)

        # 添加右车道线点（按原始顺序，反向）
        for i in range(n_points - 1, -1, -1):
            polygon_points.append(right_lane_points[i])

        # 转换为NumPy数组
        self.lane_polygon = np.array(polygon_points, dtype=np.int32)

    def is_point_in_lane(self, point):
        if self.lane_polygon is None or len(self.lane_polygon) < 3:
            return True

        # 精确计算点到多边形边界的距离
        distance = cv2.pointPolygonTest(self.lane_polygon, point, True)
        return distance >= -self.threshold

    def detect_accidents(self, frame, tracks, frame_width, frame_height):
        """检测离开道路事件（严格保持之前正确版本）"""
        annotated_frame = frame.copy()
        current_accidents = []

        if self.lane_polygon is None:
            return annotated_frame, current_accidents

        # 处理每个车辆轨迹
        for track_id, track in tracks.items():
            if not track:
                continue

            # 计算缩放比例
            scale_x = self.bird_view_width / frame_width
            scale_y = self.bird_view_height / frame_height

            # 转换最新位置到鸟瞰图坐标
            current_pos = track[-1]
            birdview_pos = (int(current_pos[0] * scale_x), int(current_pos[1] * scale_y))

            # 初始化车辆历史记录
            if track_id not in self.vehicle_history:
                self.vehicle_history[track_id] = deque(maxlen=5)

            # 检查当前点是否在车道内
            in_lane = self.is_point_in_lane(birdview_pos)
            self.vehicle_history[track_id].append(in_lane)

            # 检测离开道路事件
            if not in_lane:
                if len(self.vehicle_history[track_id]) >= self.min_out_frames:
                    all_outside = all(not state for state in self.vehicle_history[track_id])
                    if all_outside:
                        accident_type = "leave road"
                        current_accidents.append((f"车辆 {track_id}", accident_type))
                        self._draw_accident(annotated_frame, current_pos, accident_type)

        # 存储检测到的事故
        if current_accidents:
            self.detected_accidents.extend(current_accidents)

        return annotated_frame, current_accidents

    def _draw_accident(self, frame, position, accident_type):
        x, y = int(position[0]), int(position[1])
        cv2.circle(frame, (x, y), 20, (0, 0, 255), 3)
        cv2.line(frame, (x - 15, y - 15), (x + 15, y + 15), (0, 0, 255), 2)
        cv2.line(frame, (x - 15, y + 15), (x + 15, y - 15), (0, 0, 255), 2)
        cv2.putText(frame, accident_type, (x - 40, y - 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)

    def get_accident_history(self):
        return self.detected_accidents

    def reset(self):
        """重置检测器状态"""
        self.detected_accidents = []
        self.vehicle_history.clear()